#include"Camera.h"
#include"Game.h"

#include<vector>

namespace Craft
{

	Camera::Camera(Game* game, glm::vec3 postion, glm::vec3 up, GLfloat yaw, GLfloat pitch) :
		m_game(game),
		m_Position(postion),
		m_WorldUp(up),
		m_Front(glm::vec3(0.0f, 0.0f, 1.0f)),
		m_Yaw(yaw),
		m_Pitch(pitch),
		MovementSpeed(SPEED),
		MouseSensivitity(SENSITIBTY),
		m_width(.8f),		// the bottom face is a quad
		m_height(1.8f),
		m_speed(0.0f),
		m_transform(0.0f)
	{
		m_Box = AABB(glm::vec3(m_Position.x - 0.4f, m_Position.y - 1.0, m_Position.z - 0.4),
					 glm::vec3(m_Position.x + 0.4f, m_Position.y + 0.5, m_Position.z + 0.4));
		this->updateCamera();
	}

	Camera::Camera(Game* game, GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch) :
		m_game(game),
		m_Position(glm::vec3(posX, posY, posZ)),
		m_WorldUp(glm::vec3(upX, upY, upZ)),
		m_Front(glm::vec3(0.0f, 0.0f, 1.0f)),
		m_Yaw(yaw),
		m_Pitch(pitch),
		MovementSpeed(SPEED),
		MouseSensivitity(SENSITIBTY),
		m_width(.8f),
		m_height(1.8f),
		m_speed(0.0f),
		m_transform(0.0f)
	{
		//m_Box = AABB(m_Position, glm::vec3(m_Position.x + m_width, m_Position.y + m_height, m_Position.z + m_width));
	//	m_Box = AABB(m_Position - 0.5f, m_Position + 0.5f);
		m_Box = AABB(glm::vec3(m_Position.x - 0.4f, m_Position.y - 1.0, m_Position.z - 0.4),
			glm::vec3(m_Position.x + 0.4f, m_Position.y + 0.5, m_Position.z + 0.4));
		this->updateCamera();
	}

	glm::vec3 Camera::getDirection()const
	{
		return m_Front;
	}

	glm::mat4 Camera::getViewMatrix()const
	{
		return glm::lookAt(m_Position, m_Position + m_Front, m_Up);
	}

	/*
		@brief 相机响应键盘事件
			   此处，因为普通移动不对y轴方向产生影响
	*/
	void Camera::processKeyBoard(Camera_Movement direction, GLfloat deltaTime)
	{
		GLfloat velocity = MovementSpeed * deltaTime;

		if (direction == FORWARD)
			m_transform += glm::vec3(m_Front.x, 0, m_Front.z) * velocity;
		if (direction == BACKWARD)
			m_transform -= glm::vec3(m_Front.x, 0, m_Front.z) * velocity;
		if (direction == LEFT)
			m_transform += glm::vec3(m_Right.x, 0, m_Right.z)* velocity;
		if (direction == RIGHT)
			m_transform -= glm::vec3(m_Right.x, 0, m_Right.z)* velocity;
	}

	/*
		@brief 相机处理鼠标事件
	*/
	void Camera::processMouseMovement(GLfloat xoffset, GLfloat yoffset, GLfloat deltaTime, GLboolean constrainPitch)
	{

		xoffset *= MouseSensivitity ;
		yoffset *= MouseSensivitity ;

		m_Yaw += xoffset;
		m_Pitch -= yoffset;

		// 限制仰视角
		if (m_Pitch > 89.0f)
		{
			m_Pitch = 89.0f;
		}
		if (m_Pitch < -89.0f)
		{
			m_Pitch = -89.0f;
		}

		updateCamera();
	}

	/*
		@brief 更新相机的朝向
	*/
	void Camera::updateCamera()
	{
		glm::vec3 front;
		front.x = -cos(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch));
		front.y = sin(glm::radians(m_Pitch));
		front.z = -cos(glm::radians(m_Pitch)) * sin(glm::radians(m_Yaw));

		m_Front = glm::normalize(front);
		m_Right = glm::normalize(glm::cross(m_WorldUp, m_Front));
		m_Up = -glm::normalize(glm::cross(m_Right, m_Front));
	}

	void Camera::setPostion(glm::vec3 position)
	{
		m_Position = position;
	}

	glm::vec3 Camera::getPostion()const
	{
		return m_Position;
	}

	void Camera::accelerateX(GLfloat dt)
	{
		m_transform.x += dt;
	}

	void Camera::accelerateY(GLfloat dt)
	{
		m_transform.y += dt ;
	}

	void Camera::accelerateZ(GLfloat dt)
	{
		m_transform.z += dt;
	}

	/*
		@brief 相机更新，包括相机的移动和对相机包围的碰撞盒和周围碰撞体进行碰撞检测
	*/
	void Camera::update()
	{
		glm::vec3 orgin_transform = m_transform;
		std::vector<AABB> hitBoxes = m_game->get_world()->get_hitBoxes(m_Box.expend(m_transform));
		

		// x axis
		for (auto& box : hitBoxes)
		{
			m_transform.x = box.get_EffectOnClipX(m_Box, m_transform.x);
		}
		m_Position.x += m_transform.x;
		m_Box.move(glm::vec3(m_transform.x, 0.0f, 0.0f));
		if (m_transform.x != orgin_transform.x)m_transform.x = 0.0f;


		// y axis
		for (auto& box : hitBoxes)
		{
			m_transform.y = box.get_EffectOnClipY(m_Box, m_transform.y);
		}
		m_Position.y += m_transform.y;
		m_Box.move(glm::vec3(0.0f,m_transform.y, 0.0f));
		//if (m_transform.y != orgin_transform.y)
		//	m_transform.y = 0.0f;
		
			
		// z axis
		for (auto& box : hitBoxes)
		{
			m_transform.z = box.get_EffectOnClipZ(m_Box, m_transform.z);
		}
		m_Position.z += m_transform.z;
		m_Box.move(glm::vec3(0.0f, 0.0f,m_transform.z));
		if (m_transform.z != orgin_transform.z)m_transform.z = 0.0f;

		//printf("center pos x: %f  y:%f z%f\n", m_Position.x, m_Position.y, m_Position.z);
		//printf("AABB   pos x: %f  y:%f z%f\n", m_Box.m_min.x, m_Box.m_min.y, m_Box.m_min.z);


		m_transform *= 0.3f;


		

	}

}